package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author: 李旭
 * @create: 2021-07-10 11:16
 **/
@Service
public class TestServiceImpl implements TestService {

    //本地锁
    private final Lock lock = new ReentrantLock();
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public void testLock() {// 5000 次   并发 100人   100 100 100 100
        //分布锁  setnx  : 如果 set k 已经存在了 就不set  如果 set k 不存在  就set
        String uuid = UUID.randomUUID().toString();
        Boolean flag = redisTemplate.opsForValue().setIfAbsent("lock", uuid
           ,3, TimeUnit.SECONDS);//死锁
        if(flag){
            //获取到了锁
            Integer num = (Integer) redisTemplate.opsForValue().get("num");
            num++;
            redisTemplate.opsForValue().set("num",num);
            //释放锁
        /*    Object v = redisTemplate.opsForValue().get("lock");
            if(uuid.equals(v)){
                //自己的锁
                redisTemplate.delete("lock"); //误删锁
            }*/
            //原子性  LUA脚本   Nginx使用LUA C++   Redis LUA脚本   C语言
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return tostring(redis.call('del',KEYS[1])) else return 0 end";
            this.redisTemplate.execute(new DefaultRedisScript<>(script), Collections.singletonList("lock"), uuid);
        }else{
            //重新获取   不见不散
            testLock();
        }
    }
/*    @Override
    public void testLock() {// 5000 次   并发 100人   100 100 100 100
        lock.lock();
        Integer num = (Integer) redisTemplate.opsForValue().get("num");
        num++;
        redisTemplate.opsForValue().set("num",num);
        lock.unlock();
    }*/
}
